#include <faker/render/System.h>

using namespace Faker::Render;

bool System::InitResources()
{
    shader.CreateFromFilePath("/home/fanbangzhen/source/ls_app/shader/3d.vert", "/home/fanbangzhen/source/ls_app/shader/singleColor.frag");

    camera.SetPosition(glm::vec3(30.0f));
    camera.LookAt(glm::vec3(0.0f), Math::Transform::Yup());
    camera.aspect = 1.33f;
    camera.fovy = 45.0f;
    camera.nFar = 1000.0f;
    camera.nNear = 0.1f;

    passBuffer.CreateFrom<PassData>(0);
    objBuffer.CreateFrom<ObjData>(1);
    matBuffer.CreateFrom<MatData>(2);

    auto cubeMeshData = Math::Geometry::CreateBox<Faker::Basic::VertexPosNormalTex, unsigned int>();
    mesh.CreateVertexIndiceInputLayout<Faker::Basic::VertexPosNormalTex, unsigned int>(cubeMeshData.vertexVec, cubeMeshData.indexVec);

    return true;
}


void System::RenderFrame(const Faker::Scene& inst) 
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);

    const auto &view = inst.m_Registry.view<Faker::Basic::Transform::Inst, Faker::Render::Mesh::Box::Inst, Faker::Render::Material::SimpleColor::Inst>();

    shader.Use();
    shader.Bind("PassBuffer", 0);
    shader.Bind("ObjBuffer", 1);
    shader.Bind("MatBuffer", 2);

    passData.proj = camera.GetProjection();
    passData.view = camera.GetViewMatrix();
    passData.camPos = camera.position;
    passBuffer.Upload(passData);

    for (const auto &e : view)
    {

        const auto &transform = inst.m_Registry.get<Faker::Basic::Transform::Inst>(e);
        const auto &meshBox = inst.m_Registry.get<Faker::Render::Mesh::Box::Inst>(e);
        const auto &mat = inst.m_Registry.get<Faker::Render::Material::SimpleColor::Inst>(e);

        objData.world = transform.world.GetWorld();
        objData.normalMatrix = glm::transpose(glm::inverse(objData.world));

        objBuffer.Upload(objData);

        matData.color = mat.mColor;
        matBuffer.Upload(matData);

        mesh.DrawElements();
    }
};

bool System::ReleaseResources()
{

    return true;
}



void System::OnFrameBufferSize(int width, int height)
{
    camera.SetAspect((float)width/(float)height);
}

